﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Castle.DynamicProxy;
using System.Reflection;

namespace Project.Util.Proxy
{

    public class DelegateWrapper
    {
        public static T WrapAs<T>(Delegate impl) where T : class
        {
            var generator = new ProxyGenerator();
            var proxy = generator.CreateInterfaceProxyWithoutTarget(typeof(T), new MethodInterceptor(impl));
            return (T)proxy;
        }
    }


    //internal class DelegateSelector : IInterceptorSelector
    //{
    //    public IInterceptor[] SelectInterceptors(Type type, MethodInfo method, IInterceptor[] interceptors)
    //    {
    //        foreach (var interceptor in interceptors)
    //        {
    //            var methodInterceptor = interceptor as MethodInterceptor;
    //            if (methodInterceptor == null)
    //                continue;
    //            var d = methodInterceptor.Delegate;
    //            if (IsEquivalent(d, method))
    //                return new[] { interceptor };
    //        }
    //        throw new ArgumentException();
    //    }

    //    private static bool IsEquivalent(Delegate d, MethodInfo method)
    //    {
    //        var dm = d.Method;
    //        if (!method.ReturnType.IsAssignableFrom(dm.ReturnType))
    //            return false;
    //        var parameters = method.GetParameters();
    //        var dp = dm.GetParameters();
    //        if (parameters.Length != dp.Length)
    //            return false;
    //        for (int i = 0; i < parameters.Length; i++)
    //        {
    //            //BUG: does not take into account modifiers (like out, ref...)
    //            if (!parameters[i].ParameterType.IsAssignableFrom(dp[i].ParameterType))
    //                return false;
    //        }
    //        return true;
    //    }
    //}

    internal class MethodInterceptor : IInterceptor
    {
        private readonly Delegate _impl;

        public MethodInterceptor(Delegate @delegate)
        {
            this._impl = @delegate;
        }

        public void Intercept(IInvocation invocation)
        {
            var result = this._impl.DynamicInvoke(invocation.Arguments);
            invocation.ReturnValue = result;
        }
    }
}
